#include "common.hpp"

static const char *optString = "k:h?";

static const struct option longOpts[] = {
	{ "help", no_argument, NULL, 'h' },
	{ "key", required_argument, NULL, 'n' },
	{ 0,0,0,0 }
};

int main (int argc, char* const argv[]) {
	// Objetos IPC
	ipc::semaphore_with_exceptions mutex( ftok(BASE_NAME,10),0 );
	ipc::shared_memory_with_exceptions<sGimnasio> gim( ftok(BASE_NAME,11) );

	std::stringstream ss;
	sMensaje msg;

	// Parametros
	key_t clave = 0;

	size_t actual = 0;
	int longIndex = 0;
	int option = 0;
	bool seguir = true;
	bool ayuda = false;

	// Interpretación de parametros.
	while ( (option = getopt_long(argc,argv,optString,longOpts,&longIndex) ) != EOF ) {
		switch (option) {
			case '?':
			case 'h':
			case ':':
				ayuda = true;
				break;
			case 'k':
				clave = parse<key_t>(optarg,0);
				break;
			default:
				break;
		}
	}

	if ( ayuda || clave == 0) {
		std::cerr << "Proceso de control de salidas y entradas por una puerta." << std::endl;
		std::cerr << "\tUso: " << argv[0] << " [-h] <-k natural>" << std::endl;
		std::cerr << "\tParametros:" << std::endl;
		std::cerr << "\t\t-h,--help:\tMostrar este mensaje de ayuda." << std::endl;
		std::cerr << "\t\t-k,--key:\tClave de la cola de mensajes asociada." << std::endl;

		return (ayuda) ? 0 : -1;
	}

	logger.setColor("\033[0;35m");
	try {
		// Creo la cola de mensajes aqui por que necesito utilizar la clave por parametro.
		ipc::messages_queue_with_exceptions mq(clave);

		gim.get(PERMITS);
		mutex.get(PERMITS);
		mq.get(PERMITS);

		logger << "Puerta: Inicio." << nl;
		while (seguir) {
			msg.data = '\0';
			mq.receive(msg,1);
			if (msg.data == 'E') {
				mutex.wait();

				msg.tipo = msg.origen;
				msg.origen = 1;
				if ( (*gim).cantidad < (*gim).maximo ) {
					actual = (*gim).cantidad++;

					logger << "Puerta: una persona entra. Lugares ocupados: " << actual+1 << "." << nl;
				} else {
					logger << "Puerta: el gimnasio esta lleno. Lugares ocupados: " << actual << "." << nl;
					msg.data = 'S';
				}
				mq.send(msg);
				
				mutex.signal();
			} else if (msg.data == 'S') {
				mutex.wait();

				msg.tipo = msg.origen;
				msg.origen = 1;
				if ((*gim).cantidad > 0) {
					actual = (*gim).cantidad--;

					logger << "Puerta: una persona sale. Lugares ocupados: " << actual-1 << "." << nl;
					mq.send(msg);
				} else {
					logger << "Puerta: error de logica, alguien desea salir pero el gimnasio esta vacio." << nl;
					mq.send(msg);
				}
				mutex.signal();
			}
		}
		logger << "Puerta: Fin." << nl;
	} catch (ipc::exception& e) {
		logger << "Puerta: " << e.what() << "." << nl;
	}

	return 0;
}
